package org.application;

import lombok.extern.slf4j.Slf4j;
import org.application.Entity.Piece;
import org.application.controller.GameController;
import org.application.enums.PieceNameEnum;
import org.application.enums.PieceSideEnum;
import org.application.event.PieceSelectedEvent;
import org.application.factory.MoveValidatorFactory;
import org.application.listener.PieceSelectedListener;
import org.application.service.MoveValidator;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import java.util.HashMap;
import java.util.List;  // 确保导入的是java.util.List
import java.util.ArrayList;
import java.util.Map;

@Slf4j
public class ChineseChessGame {

    public static void main(String[] args) {
        // 创建主窗口
        JFrame frame = new JFrame("象棋游戏");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(600, 400);

        // 设置主窗口布局
        frame.setLayout(new BorderLayout());

        // 添加标题
        JLabel titleLabel = new JLabel("象棋游戏", JLabel.CENTER);
        titleLabel.setFont(new Font("宋体", Font.BOLD, 24));
        frame.add(titleLabel, BorderLayout.NORTH);

        // 添加开始游戏按钮
        JButton startGameButton = new JButton("开始游戏");
        startGameButton.setFont(new Font("宋体", Font.PLAIN, 18));
        startGameButton.addActionListener(e -> showChessDialog(frame));
        frame.add(startGameButton, BorderLayout.CENTER);

        frame.setLocationRelativeTo(null); // 居中显示
        frame.setVisible(true);


    }

    private static void showChessDialog(JFrame parent) {
        // 创建一个弹框
        JDialog dialog = new JDialog(parent, "象棋游戏", true);
        dialog.setSize(800, 950); // 调整窗口大小
        dialog.setLocationRelativeTo(parent);
        dialog.setLayout(new BorderLayout());

        // 添加自定义棋盘面板
        ChessBoardPanel chessBoardPanel = new ChessBoardPanel();
        dialog.add(chessBoardPanel, BorderLayout.CENTER);

        // 添加底部控制区
        JPanel controlPanel = new JPanel();
        controlPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 10));

        // 创建并注册 GameController 作为监听器
        GameController gameController = new GameController();
        chessBoardPanel.addPieceSelectedListener(gameController);

        JButton resetButton = new JButton("重新开始");
        resetButton.addActionListener(e -> chessBoardPanel.resetBoard());
        controlPanel.add(resetButton);

        JButton exitButton = new JButton("退出游戏");
        exitButton.addActionListener(e -> dialog.dispose());
        controlPanel.add(exitButton);

        dialog.add(controlPanel, BorderLayout.SOUTH);
        dialog.setVisible(true);
    }
}

@Slf4j
class ChessBoardPanel extends JPanel {
    private static final int GRID_SIZE = 80; // 棋盘格大小
    private static final int ROWS = 10; // 行数
    private static final int COLS = 9;  // 列数
    private static final int PIECE_SIZE = 20;  // 棋子大小


    // 存储棋子信息
//    private String[][] pieces; // 存储棋子信息
    // 清空棋盘
    private List<Piece> pieceList = new ArrayList<>();

    // 使用 HashMap 来存储棋子的位置信息
    private Map<String, Piece> pieceMap = new HashMap<>();

    private int selectedRow = -1; // 当前选中的棋子行
    private int selectedCol = -1; // 当前选中的棋子列
    String selectType; // 棋子的类型（如“马”，“车”等）

    public ChessBoardPanel() {
//        pieces = new String[ROWS][COLS];
        initializePieces();

        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                selectPiece(e.getX(), e.getY());
            }

            // 当鼠标释放时触发,移动方法
            @Override
            public void mouseReleased(MouseEvent e) {
                movePiece(e.getX(), e.getY());
            }
        });

        addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                dragPiece(e.getX(), e.getY());
            }
        });
    }


    private void initializePieces() {
        pieceList = new ArrayList<>();
        pieceMap = new HashMap<>();
        // 红色棋子
        addPiece(0, 0, PieceNameEnum.ROOK, PieceSideEnum.RED, false, false); // 车
        addPiece(0, 1, PieceNameEnum.KNIGHT, PieceSideEnum.RED, false, false); // 马
        addPiece(0, 2, PieceNameEnum.MINISTER, PieceSideEnum.RED, false, false); // 相
        addPiece(0, 3, PieceNameEnum.ADVISOR, PieceSideEnum.RED, false, false); // 仕
        addPiece(0, 4, PieceNameEnum.KING, PieceSideEnum.RED, false, false); // 帅
        addPiece(0, 5, PieceNameEnum.ADVISOR, PieceSideEnum.RED, false, false); // 仕
        addPiece(0, 6, PieceNameEnum.MINISTER, PieceSideEnum.RED, false, false); // 相
        addPiece(0, 7, PieceNameEnum.KNIGHT, PieceSideEnum.RED, false, false); // 马
        addPiece(0, 8, PieceNameEnum.ROOK, PieceSideEnum.RED, false, false); // 车
        addPiece(2, 1, PieceNameEnum.CANNON, PieceSideEnum.RED, false, false); // 炮
        addPiece(2, 7, PieceNameEnum.CANNON, PieceSideEnum.RED, false, false); // 炮
        addPiece(3, 0, PieceNameEnum.PAWN, PieceSideEnum.RED, false, false); // 兵
        addPiece(3, 2, PieceNameEnum.PAWN, PieceSideEnum.RED, false, false); // 兵
        addPiece(3, 4, PieceNameEnum.PAWN, PieceSideEnum.RED, false, false); // 兵
        addPiece(3, 6, PieceNameEnum.PAWN, PieceSideEnum.RED, false, false); // 兵
        addPiece(3, 8, PieceNameEnum.PAWN, PieceSideEnum.RED, false, false); // 兵

// 黑色棋子
        addPiece(9, 0, PieceNameEnum.ROOK, PieceSideEnum.BLACK, false, false); // 車
        addPiece(9, 1, PieceNameEnum.KNIGHT, PieceSideEnum.BLACK, false, false); // 馬
        addPiece(9, 2, PieceNameEnum.ELEPHANT, PieceSideEnum.BLACK, false, false); // 象
        addPiece(9, 3, PieceNameEnum.ADVISOR, PieceSideEnum.BLACK, false, false); // 士
        addPiece(9, 4, PieceNameEnum.GENERAL, PieceSideEnum.BLACK, false, false); // 將
        addPiece(9, 5, PieceNameEnum.ADVISOR, PieceSideEnum.BLACK, false, false); // 士
        addPiece(9, 6, PieceNameEnum.ELEPHANT, PieceSideEnum.BLACK, false, false); // 象
        addPiece(9, 7, PieceNameEnum.KNIGHT, PieceSideEnum.BLACK, false, false); // 馬
        addPiece(9, 8, PieceNameEnum.ROOK, PieceSideEnum.BLACK, false, false); // 車
        addPiece(7, 1, PieceNameEnum.CANNON, PieceSideEnum.BLACK, false, false); // 砲
        addPiece(7, 7, PieceNameEnum.CANNON, PieceSideEnum.BLACK, false, false); // 砲
        addPiece(6, 0, PieceNameEnum.SOLDIER, PieceSideEnum.BLACK, false, false); // 卒
        addPiece(6, 2, PieceNameEnum.SOLDIER, PieceSideEnum.BLACK, false, false); // 卒
        addPiece(6, 4, PieceNameEnum.SOLDIER, PieceSideEnum.BLACK, false, false); // 卒
        addPiece(6, 6, PieceNameEnum.SOLDIER, PieceSideEnum.BLACK, false, false); // 卒
        addPiece(6, 8, PieceNameEnum.SOLDIER, PieceSideEnum.BLACK, false, false); // 卒


    }


    private void addPiece(int x, int y, PieceNameEnum name, PieceSideEnum side, boolean isSelected, boolean isCaptured) {
        Piece piece = Piece.builder()
                .x(x)
                .y(y)
                .name(name)
                .side(side)
                .isSelected(isSelected)
                .isCaptured(isCaptured) // 新增字段
                .build();
        pieceList.add(piece);
        pieceMap.put(x + "," + y, piece);
    }


    private final List<PieceSelectedListener> listenerList = new ArrayList<>();

    public void addPieceSelectedListener(PieceSelectedListener listener) {
        listenerList.add(listener);
    }

    public void removePieceSelectedListener(PieceSelectedListener listener) {
        listenerList.remove(listener);
    }

    private void selectPiece(int x, int y) {
        // 计算点击的棋盘行列
        int col = (x - (GRID_SIZE / 2)) / GRID_SIZE;
        int row = (y - (GRID_SIZE / 2)) / GRID_SIZE;

        // 检查是否在棋盘范围内
        if (isWithinBoard(row, col)) {
            String position = row + "," + col;
            Piece clickedPiece = pieceMap.get(position); // 使用 HashMap 获取棋子
            log.info("选中棋子 clickedPiece: {}", clickedPiece);

            // 如果两次选中的棋子是一样的，直接返回
            if (selectedRow == row && selectedCol == col) {
                log.info("两次选中的是同一棋子，无需更改状态");
                return;
            }

            if (clickedPiece != null) {
                handlePreviousSelection();

                // 设置新的选中状态
                clickedPiece.setSelected(true);
                log.info("棋子选中, 设置选中状态 clickedPiece: {}", clickedPiece);

                updateSelectedPosition(row, col);
                notifyListeners(row, col);
            }
        }

        // 更新棋盘显示
        repaint();
    }

    private boolean isWithinBoard(int row, int col) {
        return row >= 0 && row < ROWS && col >= 0 && col < COLS;
    }

    private void handlePreviousSelection() {
        if (selectedRow != -1 && selectedCol != -1) {
            String prevPosition = selectedRow + "," + selectedCol;
            Piece prevSelectedPiece = pieceMap.get(prevPosition);

            if (prevSelectedPiece != null) {
                prevSelectedPiece.setSelected(false); // 取消选中
                log.info("取消之前选中的棋子: {}", prevSelectedPiece);
            }
        }
    }

    private void updateSelectedPosition(int row, int col) {
        selectedRow = row;
        selectedCol = col;
    }

    private void notifyListeners(int row, int col) {
        PieceSelectedEvent event = new PieceSelectedEvent(row, col);
        for (PieceSelectedListener listener : listenerList) {
            listener.onPieceSelected(event);
        }
    }




    private void dragPiece(int x, int y) {
        int col = (x - (GRID_SIZE / 2)) / GRID_SIZE;
        int row = (y - (GRID_SIZE / 2)) / GRID_SIZE;
        log.info("拖动监听,x: {},y: {},col: {},row: {}", x, y, col, row);
    }

    public void resetBoard() {
        initializePieces();
        repaint(); // 重新绘制棋盘
    }


    private void movePiece(int x, int y) {
        // 计算目标位置的行和列
        int col = (x - (GRID_SIZE / 2)) / GRID_SIZE;
        int row = (y - (GRID_SIZE / 2)) / GRID_SIZE;

        // 检查是否有选中的棋子
        if (selectedRow == -1 || selectedCol == -1) {
            log.warn("没有选中任何棋子");
            return; // 如果没有选中棋子，返回
        }

        // 检查目标位置是否在棋盘范围内
        if (row < 0 || row >= ROWS || col < 0 || col >= COLS) {
            log.warn("目标位置超出棋盘范围，移动失败");
            return; // 如果目标位置超出棋盘范围，返回
        }

        String targetKey = row + "," + col; // 目标位置的键
        String selectedKey = selectedRow + "," + selectedCol; // 当前选中棋子的位置键

        Piece selectedPiece = pieceMap.get(selectedKey); // 获取当前选中棋子
        if (selectedPiece == null) {
            log.warn("选中的棋子不存在");
            return;
        }

        MoveValidator moveValidator = MoveValidatorFactory.createMoveValidator(selectedPiece.getName());
        boolean success = moveValidator.validateMove(pieceMap, selectedPiece, selectedRow, selectedCol, row, col);
        if (!success) {
            return;
        }

        // 如果目标位置已有棋子
        if (pieceMap.containsKey(targetKey)) {
            Piece targetPiece = pieceMap.get(targetKey); // 获取目标位置的棋子

            // 如果目标棋子和选中棋子属于同一方，则禁止操作
            if (targetPiece.getSide() == selectedPiece.getSide()) {
                log.info("目标位置有己方棋子，操作无效: {} -> {}", selectedPiece, targetPiece);
                return; // 禁止吃掉己方棋子
            }

            log.info("目标位置有棋子，棋子将被吃掉: {} -> {}", selectedPiece, targetPiece);

            // 处理吃掉目标棋子的逻辑
            removePiece(selectedKey, targetKey, selectedPiece, targetPiece);
        } else {
            // 目标位置为空，直接移动棋子
            movePieceToTarget(selectedKey, targetKey, selectedPiece, row, col);
            log.info("目标位置为空，可以移动，移动棋子: {} -> ({}, {})", selectedPiece, row, col);
        }

        // 更新棋盘显示
        repaint();
    }


    private void removePiece(String selectedKey, String targetKey, Piece selectedPiece, Piece targetPiece) {
        log.info("被吃掉的棋子,targetPiece:{}",targetPiece);
        // 将目标棋子标记为已被吃掉
        targetPiece.setCaptured(true);
        pieceMap.remove(targetKey); // 从棋盘地图中移除被吃掉的棋子

        // 将选中的棋子移动到目标位置
        pieceMap.remove(selectedKey); // 从原位置移除棋子
        selectedPiece.setX(Integer.parseInt(targetKey.split(",")[0]));
        selectedPiece.setY(Integer.parseInt(targetKey.split(",")[1]));
        pieceMap.put(targetKey, selectedPiece); // 将棋子移动到目标位置
        selectedPiece.setSelected(false); // 重置选中状态
    }

    private void movePieceToTarget(String selectedKey, String targetKey, Piece selectedPiece, int row, int col) {
        pieceMap.remove(selectedKey); // 从原位置移除棋子
        selectedPiece.setX(row);
        selectedPiece.setY(col);
        pieceMap.put(targetKey, selectedPiece); // 将棋子移动到目标位置
        selectedPiece.setSelected(false); // 重置选中状态
    }


    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 绘制棋盘
        int width = (COLS - 1) * GRID_SIZE; // 棋盘宽度
        int height = (ROWS - 1) * GRID_SIZE; // 棋盘高度

        for (int i = 0; i < ROWS; i++) {
            g2d.drawLine(GRID_SIZE, GRID_SIZE + i * GRID_SIZE, GRID_SIZE + width, GRID_SIZE + i * GRID_SIZE);
        }

        for (int i = 0; i < COLS; i++) {
            if (i > 0 && i < 8) {
                g2d.drawLine(GRID_SIZE + i * GRID_SIZE, GRID_SIZE, GRID_SIZE + i * GRID_SIZE, GRID_SIZE + 4 * GRID_SIZE);
                g2d.drawLine(GRID_SIZE + i * GRID_SIZE, GRID_SIZE + 5 * GRID_SIZE, GRID_SIZE + i * GRID_SIZE, GRID_SIZE + height);
            } else {
                g2d.drawLine(GRID_SIZE + i * GRID_SIZE, GRID_SIZE, GRID_SIZE + i * GRID_SIZE, GRID_SIZE + height);
            }
        }

        // 绘制“楚河汉界”
        g2d.setFont(new Font("宋体", Font.BOLD, 30));
        g2d.setColor(Color.GRAY);
        String chuRiver = "楚河";
        String hanBorder = "汉界";
        FontMetrics fm = g2d.getFontMetrics();

        int textY = GRID_SIZE + 4 * GRID_SIZE + GRID_SIZE / 2;
        g2d.drawString(chuRiver, GRID_SIZE + 2 * GRID_SIZE - fm.stringWidth(chuRiver) / 2, textY);
        g2d.drawString(hanBorder, GRID_SIZE + 6 * GRID_SIZE - fm.stringWidth(hanBorder) / 2, textY);

        drawCrossLines(g2d);

        for (Piece piece : pieceList) {
            // 获取棋子的坐标
            int row = piece.getX();
            int col = piece.getY();

            // 判断棋子阵营并设置颜色
            Color color = (piece.getSide() == PieceSideEnum.BLACK) ? Color.BLACK : Color.RED;

            // 绘制棋子
            drawPiece(g2d, row, col, piece, color);
        }


    }

    // 绘制象棋的“米字格”交叉线
    private void drawCrossLines(Graphics2D g2d) {
        int[][] crossPoints = {
                {1, 4},  // 红方相位置
                {8, 4},   // 黑方象位置
        };

        for (int[] point : crossPoints) {
            int row = point[0];
            int col = point[1];
            int x = GRID_SIZE + col * GRID_SIZE;
            int y = GRID_SIZE + row * GRID_SIZE;

            // 画交叉线
            int crossSize = 80;
            g2d.drawLine(x - crossSize, y - crossSize, x + crossSize, y + crossSize);
            g2d.drawLine(x - crossSize, y + crossSize, x + crossSize, y - crossSize);
            g2d.setColor(Color.BLACK); // 设置交叉线为黑色
        }
    }

    private boolean isPieceSelected(Piece piece) {
        return piece.isSelected();
    }


    private void drawPiece(Graphics2D g2d, int row, int col, Piece piece, Color color) {

        // 如果棋子已被吃掉，直接返回，不渲染
        if (piece.isCaptured()) {
            return;
        }

        // 计算格子的中心位置
        int centerX = GRID_SIZE + col * GRID_SIZE;
        int centerY = GRID_SIZE + row * GRID_SIZE;

        // 计算棋子的位置
        int x = centerX - GRID_SIZE / 2 + GRID_SIZE / 4;
        int y = centerY - GRID_SIZE / 2 + GRID_SIZE / 4;
        int pieceSize = GRID_SIZE / 2;

        // 如果该棋子是选中的，绘制一个高亮边框
        if (isPieceSelected(piece)) {
            // 绘制选中效果环
            g2d.setColor(Color.GREEN);
            g2d.setStroke(new BasicStroke(3));
            g2d.drawOval(centerX - GRID_SIZE / 2, centerY - GRID_SIZE / 2, GRID_SIZE, GRID_SIZE);
        }

        // 绘制棋子主体
        // 绘制棋子圆
        g2d.setColor(color);
        g2d.fillOval(x, y, pieceSize, pieceSize);

        // 绘制棋子文字
        g2d.setColor(Color.WHITE);
        g2d.setFont(new Font("宋体", Font.BOLD, 20));

        String name = piece.getName().getValue();
        FontMetrics fm = g2d.getFontMetrics();
        int textWidth = fm.stringWidth(name);
        int textHeight = fm.getAscent();

        // 计算文本绘制位置，居中显示
        int textX = x + (pieceSize - textWidth) / 2;
        int textY = y + (pieceSize + textHeight) / 2;

        g2d.drawString(name, textX, textY);
    }


    @Override
    public Dimension getPreferredSize() {
        // 修正棋盘的实际尺寸
        return new Dimension(GRID_SIZE * COLS, GRID_SIZE * ROWS);
    }
}
